﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebAPI.Common.Attributes;
using WebAPI.Common;
using WebAPI.Controllers;
using WebAPI.DataAccess;
using WebAPI.Models;
using WebAPI.Util;
using InParkRedemptionAPI.Models;
using InParkRedemptionAPI.DataAccess;
using RapidSalesAdminPortalAPI.DataAccess;

namespace InParkRedemptionAPI.Controllers
{
    //[Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class FrIpAdministratorAccountController : ParentController
    {
        private readonly RS_AdmPortalContext _context;
        private readonly IConfiguration _configuration;
        private readonly ILogUtility _logUtility;
        private readonly ILogger _logger;
        private readonly IDataProtectorUtility _dataProtectorUntility;
        public FrIpAdministratorAccountController(RS_AdmPortalContext context, IConfiguration configuration, ILogUtility logUtility, ILogger<FrIpAdministratorAccountController> logger, IDataProtectorUtility dataProtectorUntility)
        {
            _context = context;
            _configuration = configuration;
            _logUtility = logUtility; // sample code for DI of common utility class
            _logger = logger;
            _dataProtectorUntility = dataProtectorUntility;
        }

        [HttpPost("GetAdministratorAccountList")]
        public async Task<ActionResult<ResultMsg>> GetAdministratorAccountList([FromBody] GetAdministratorAccountListRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                IQueryable<FrIpAdministratorAccount> paComont = _context.FrIpAdministratorAccounts.Include(x=>x.OperationArea).Where(x => x.IsSuperAdmin == false && x.IsDelete == false).AsQueryable();
                if (!string.IsNullOrWhiteSpace(requestModel.Enable))
                    paComont = paComont.Where(x => x.Enable.ToString() == requestModel.Enable);
                if (!string.IsNullOrWhiteSpace(requestModel.AccountName))
                    paComont = paComont.Where(x => x.AccountName.Contains(requestModel.AccountName));
                if (!string.IsNullOrWhiteSpace(requestModel.LoginName))
                    paComont = paComont.Where(x => x.LoginName.Contains(requestModel.LoginName));
                if (!string.IsNullOrWhiteSpace(requestModel.Email))
                    paComont = paComont.Where(x => x.Email.Contains(requestModel.Email));
                if (requestModel.OperationAreaId != Guid.Empty && requestModel.OperationAreaId != null)
                    paComont = paComont.Where(x => x.OperationAreaId == requestModel.OperationAreaId);
                if (!string.IsNullOrWhiteSpace(requestModel.ProductControl))
                    paComont = paComont.Where(x => x.ProductControl.ToString() == requestModel.ProductControl);

                var paData = paComont.ToList().Select(x => new GetAdministratorAccountListResponse()
                {
                    AccountID = x.Id,
                    AccountName = x.AccountName,
                    LoginName = x.LoginName,
                    Email = x.Email,
                    Enable = x.Enable,
                    OperationArea = x.OperationArea == null ? "" : x.OperationArea.Value,
                    OperationAreaId = x.OperationAreaId,
                    ProductControl = x.ProductControl,
                    CreateDate = x.CreateDate.ToString("yyyy-MM-dd HH:mm:ss"),
                    UpdateDate = x.UpdateDate.ToString("yyyy-MM-dd HH:mm:ss"),
                    CreateUser = UserNameQuery(x.CreateUser.GetValueOrDefault()),
                    UpdateUser = UserNameQuery(x.UpdateUser.GetValueOrDefault())
                }).AsQueryable();

                if (!string.IsNullOrWhiteSpace(requestModel.Field) && paComont.Count() > 0)
                    paData = DBHelper.DataSorting(paData, requestModel.Field, requestModel.Order);
                else
                    paData = DBHelper.DataSorting(paData, "CreateDate", "desc");

                var AdministratorAccount = await BasePageOutputExtensions.ToPagedListAsync(paData.ToList(), requestModel.Page, requestModel.PageSize);

                return resultMsg.SetResultMsg(
                     (int)ResultCode.Success,
                     HelperUtility.GetDescription(ResultCode.Success),
                     AdministratorAccount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                     (int)ResultCode.ErrorOnRequestUnMarshalling,
                     HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                     null);
            }
        }


        [HttpGet("{id}")]
        public async Task<ActionResult<ResultMsg>> GetAdministratorAccount(Guid id)
        {
            var resultMsg = new ResultMsg();
            try
            {
                FrIpAdministratorAccount pa = await _context.FrIpAdministratorAccounts.Include(x => x.OperationArea).FirstOrDefaultAsync(x => x.Id == id);
                if (pa == null)
                {
                    return resultMsg.SetResultMsg(
                         (int)ResultCode.UserNotFound,
                         HelperUtility.GetDescription(ResultCode.UserNotFound),
                         null);
                }

                var AdministratorAccount = new GetAdministratorAccountListResponse()
                {
                    AccountID = pa.Id,
                    AccountName = pa.AccountName,
                    LoginName = pa.LoginName,
                    Email = pa.Email,
                    Enable = pa.Enable,
                    ProductControl = pa.ProductControl,
                    OperationArea = pa.OperationArea == null ? "" : pa.OperationArea.Value,
                    OperationAreaId = pa.OperationAreaId,
                    CreateDate = pa.CreateDate.ToString("yyyy-MM-dd HH:mm:ss"),
                    UpdateDate = pa.UpdateDate.ToString("yyyy-MM-dd HH:mm:ss"),
                    CreateUser = UserNameQuery(pa.CreateUser.GetValueOrDefault()),
                    UpdateUser = UserNameQuery(pa.UpdateUser.GetValueOrDefault())
                };
                return resultMsg.SetResultMsg(
                     (int)ResultCode.Success,
                     HelperUtility.GetDescription(ResultCode.Success),
                     AdministratorAccount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                     (int)ResultCode.ErrorOnRequestUnMarshalling,
                     HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                     null);
            }
        }


        [HttpGet("GetAdministratorAccountAll")]
        public async Task<ActionResult<ResultMsg>> GetAdministratorAccountName()
        {
            var resultMsg = new ResultMsg();
            try
            {
                List<string> list = await _context.FrIpAdministratorAccounts.Select(x => x.LoginName).ToListAsync();
                return resultMsg.SetResultMsg(
                     (int)ResultCode.Success,
                     HelperUtility.GetDescription(ResultCode.Success),
                     list);
            }
            catch (Exception)
            {
                return resultMsg.SetResultMsg(
                     (int)ResultCode.ErrorOnRequestUnMarshalling,
                     HelperUtility.GetDescription(ResultCode.UserNotFound),
                     null);
            }
        }


        [Log("AdministratorAccount", "UpdateAdministratorAccount", description: "AdministratorAccount/UpdateAdministratorAccount", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPut("UpdateAdministratorAccount")]
        public async Task<ActionResult<ResultMsg>> UpdateAdministratorAccount([FromBody] UpdateAdministratorAccountRequest AdministratorAccount)
        {
            var resultMsg = new ResultMsg();
            try
            {
                if (!AdministratorAccountExists(AdministratorAccount.AccountId))
                {
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.UserNotFound,
                     HelperUtility.GetDescription(ResultCode.UserNotFound),
                     null);
                }
                if (!string.IsNullOrEmpty(AdministratorAccount.Password) && !AdministratorAccount.Password.Equals(AdministratorAccount.ConfirmPassword))
                {
                    await _context.SaveChangesAsync();
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.NewPasswordAndConfirmAreNotMatching,
                     HelperUtility.GetDescription(ResultCode.NewPasswordAndConfirmAreNotMatching),
                     null);
                }
                FrIpAdministratorAccount dt = await _context.FrIpAdministratorAccounts.FirstOrDefaultAsync(x => x.Id == AdministratorAccount.AccountId);
                dt.AccountName = AdministratorAccount?.AccountName;
                dt.Password = !string.IsNullOrWhiteSpace(AdministratorAccount.Password) ? MD5Encryption.Encrypt(AdministratorAccount.Password) : dt.Password;
                dt.Enable = AdministratorAccount.Enable;
                dt.Email = AdministratorAccount?.Email;
                dt.ProductControl = AdministratorAccount.ProductControl;
                dt.OperationAreaId = AdministratorAccount?.OperationAreaId;
                dt.UpdateUser = CurrentUserId;
                dt.UpdateDate = DateTime.Now;
                _context.Entry(dt).State = EntityState.Modified;
                await _context.SaveChangesAsync();
                return resultMsg.SetResultMsg(
                  (int)ResultCode.Success,
                  HelperUtility.GetDescription(ResultCode.Success),
                  null);
            }
            catch (Exception ex)
            {
                _logger.LogError("AdministratorAccount/UpdateAdministratorAccount Error:" + ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.UserNotFound),
                 null);
            }
        }


        [Log("AdministratorAccount", "AddAdministratorAccount", description: "AdministratorAccount/AddAdministratorAccount", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPost("AddAdministratorAccount")]
        public async Task<ActionResult<ResultMsg>> AddAdministratorAccount([FromBody] AddAdministratorAccountRequest AdministratorAccount)
        {
            var resultMsg = new ResultMsg();
            try
            {

                if (AdministratorAccountExists(AdministratorAccount.LoginName))
                {
                    await _context.SaveChangesAsync();
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.AccountAlreadyExist,
                     HelperUtility.GetDescription(ResultCode.AccountAlreadyExist),
                     null);
                }
                if (!AdministratorAccount.Password.Equals(AdministratorAccount.ConfirmPassword))
                {
                    await _context.SaveChangesAsync();
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.NewPasswordAndConfirmAreNotMatching,
                     HelperUtility.GetDescription(ResultCode.NewPasswordAndConfirmAreNotMatching),
                     null);
                }

                DateTime NowTime = DateTime.Now;
                FrIpAdministratorAccount dt = new FrIpAdministratorAccount()
                {
                    Id = Guid.NewGuid(),
                    AccountName = AdministratorAccount.AccountName,
                    LoginName = AdministratorAccount.LoginName,
                    Email = AdministratorAccount.Email,
                    Password = MD5Encryption.Encrypt(AdministratorAccount.Password),
                    ProductControl = AdministratorAccount.ProductControl,
                    OperationAreaId = AdministratorAccount.OperationAreaId, //string.IsNullOrWhiteSpace(AdministratorAccount.OperationAreaId) ? Guid.Empty :  AdministratorAccount.OperationAreaId,
                    Enable = AdministratorAccount.Enable,
                    LoginFailedCount = 0,
                    CreateUser = CurrentUserId,
                    UpdateUser = CurrentUserId,
                    CreateDate = NowTime,
                    UpdateDate = NowTime
                };
                _context.FrIpAdministratorAccounts.Add(dt);
                await _context.SaveChangesAsync();
                return resultMsg.SetResultMsg(
                 (int)ResultCode.Success,
                 HelperUtility.GetDescription(ResultCode.Success),
                 null);
            }
            catch (Exception ex)
            {
                _logger.LogError("AdministratorAccount/AddAdministratorAccount Error:" + ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 null);
            }
        }


        [Log("AdministratorAccount", "DeleteAdministratorAccount", description: "AdministratorAccount/DeleteAdministratorAccount", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpDelete("DeleteAdministratorAccount")]
        public async Task<ActionResult<ResultMsg>> DeleteAdministratorAccount([FromBody] EnableAdministratorAccountRequest AdministratorAccount)
        {
            ResultMsg resultMsg = new();
            List<FrIpAdministratorAccount> paDt = await _context.FrIpAdministratorAccounts?.Where(x => AdministratorAccount.accountIds.Contains(x.Id.ToString()))?.ToListAsync();
            if (paDt == null || paDt.Count < 1)
            {
                return resultMsg.SetResultMsg(
                 (int)ResultCode.NoMatchForThisAccount,
                 HelperUtility.GetDescription(ResultCode.NoMatchForThisAccount),
                 null);
            }
            DateTime nowTime = DateTime.Now;
            for (int i = 0; i < paDt.Count; i++)
            {
                paDt[i].IsDelete = true;
                paDt[i].UpdateDate = nowTime;
                paDt[i].UpdateUser = CurrentUserId;
            }
            await _context.SaveChangesAsync();
            return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                null);
        }


        [Log("AdministratorAccount", "EnableAdministratorAccount", description: "AdministratorAccount/EnableAdministratorAccount", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPut("EnableAdministratorAccount")]
        public async Task<ActionResult<ResultMsg>> EnableAdministratorAccount([FromBody] EnableAdministratorAccountRequest requestModel)
        {
            ResultMsg resultMsg = new();
            var accountList = _context.FrIpAdministratorAccounts.Where(x => requestModel.accountIds.Contains(x.Id.ToString())).ToList();
            if (accountList == null || accountList.Count <= 0)
            {
                return resultMsg.SetResultMsg(
               (int)ResultCode.UserNotFound,
               HelperUtility.GetDescription(ResultCode.UserNotFound),
               null);
            }
            foreach (var account in accountList)
            {
                account.Enable = requestModel.enable;
                account.ProductControl = requestModel.ProductControl;
                if (requestModel.enable)
                    account.LoginFailedCount = 0;
            }
            await _context.SaveChangesAsync();
            return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                null);
        }

        [NonAction]
        private bool AdministratorAccountExists(Guid id)
        {
            return _context.FrIpAdministratorAccounts.Any(e => e.Id == id);
        }

        [NonAction]
        private bool AdministratorAccountExists(string LoginName)
        {
            return _context.FrIpAdministratorAccounts.Any(e => e.LoginName == LoginName);
        }

        [NonAction]
        public string UserNameQuery(Guid id)
        {
            FrIpAdministratorAccount dt = _context.FrIpAdministratorAccounts?.FirstOrDefault(x => x.Id.Equals(id));
            return dt?.AccountName ?? "";
        }
    }
}
